#pragma once
#include "mc/deps/core/common/bedrock/typeid_t.h"
#include <include.h>
using namespace std;

#define ISINTERCEPT if(!isInLand || !land->id || land->owner == uuid) return true;  //领地主人 

#define LASTIME(h,m)                                                                                              \
    localtime_s(&now_tm, &now_time);                                                                              \
    if(now_tm.tm_hour >= h && now_tm.tm_min >= m) now_tm.tm_mday += 1;                                            \
    now_tm.tm_hour = h;                                                                                           \
    now_tm.tm_min  = m;                                                                                           \
    now_tm.tm_sec  = 0;                                                                                           \
    duration       = chrono::system_clock::from_time_t(mktime(&now_tm)) - now;                                    \
    milliseconds   = chrono::duration_cast<chrono::milliseconds>(duration).count();                               \
    cout <<"距离"<<setfill('0')<<setw(2)<<h<<':'<<setfill('0')<<setw(2)<<m<<"还有 "<<milliseconds<<" 毫秒"<<endl;  \
    timeTask.add<ll::schedule::DelayTask>(                                                                        \
        chrono::milliseconds(milliseconds),[](){                                                                  \
            lock_guard<mutex> lock(LLmutex);                                                                      \
                timeTask.add<ll::schedule::RepeatTask>(                                                           \
                    chrono::milliseconds(oneDayMilliseconds),[](){
#define LASTIME_END });});
#define REDUCE_MONEY(money) if(LLMoney_Get(xuid) < money) {
#define REDUCE_MONEY_END(money) return; } LLMoney_Reduce(xuid, money);

inline namespace XUtils {
    //CMD xland
    enum SetPoint : int {setPt = 0, setPt1 = 1, setPt2 = 2, start = 3, stop = 4};
    enum SetLand  : int {perm  = 0, land   = 1};
    struct XLandCmd {
        SetPoint                setPoint;
        SetLand                 setLand;
        CommandSelector<Player> player;
        CommandPositionFloat    pos;
        Json::Value             json;
        int                     landId;
    };

    void regEvent();                                                 //注册事件
    void removeEvent();                                              //移除事件
    void regXLandCmd();                                              //注册领地指令
    void newTaskAll();                                               //全局计划任务

    static inline string getPlayerLangCode(Player& player) {
        try {
            auto& requestJson = ll::service::getServerNetworkHandler()
                    ->fetchConnectionRequest(ll::service::getLevel()->getPlayer(player.getOrCreateUniqueID())->getNetworkIdentifier())
                    .mRawToken->mDataInfo;
            return requestJson.get("LanguageCode", "unknown").asString("unknown");
        }  catch (...) {return "Fail in getLangCode!";}
    }   //获取langCode
    static inline vector<string> stringToArr(const string& str, char line = ','){
        vector<string> arr;
        stringstream ss(str);
        string temp;
        while(getline(ss, temp, line)) arr.push_back(temp);
        return arr;
    }   //字符串转Arr
    static inline Vec3 stringToVec3(const string& str) {
        if(str.empty()) return 0;
        auto point = stringToArr(str);
        return Vec3(stoi(point[0]), stoi(point[1]), stoi(point[2]));
    }   //字符串转Vec3
    static inline string arrToStr(vector<string>& arr, char line = ',') {
        string str("");
        for(const auto& item : arr) str += fmt::format("{}{}", item, line);
        str.pop_back();
        return str;
    }
    static inline string getArrStr(vector<string>& arr, string str = "", char line = ',') {
        if(arr.empty()) return "none";
        const auto beginItem = *(arr.begin());
        const auto endItem   = *(arr.end()-1);
        if(endItem == "all" || endItem == "none") return endItem;
        for(auto it = arr.begin(); it != arr.end(); it++) {
            if(*it=="null"||*it=="all"||*it=="none"||find(arr.begin(),it,*it)!=it||*it=="") continue;
            str += *it;
            str.push_back(line);
        }
        if(arr.empty()) return beginItem == "null" ? "none" : beginItem;
        if(str.empty()) return "none";
        str.pop_back(); return str;
    }   //获取字符串
    static inline string& stringRemoveBE(string& str) {
        str.erase(0, 1);
        str.pop_back();
        return str;
    }   //去除字符串两端
    static inline string asString(const optional<string>& opt_str) {
        return opt_str.has_value() ? opt_str.value() : "无";
    }
    static inline void toMaxMin(Vec3& occupyPt1, Vec3& occupyPt2) {
        int index=0;
        Vec3 minPt,maxPt;
        if (occupyPt1 != 0) index += 1;
        if (occupyPt2 != 0) index += 2;
        if (index == 3) {
            if (occupyPt1.x < occupyPt2.x) index += 4;    //1
            if (occupyPt1.y < occupyPt2.y) index += 8;    //2
            if (occupyPt1.z < occupyPt2.z) index += 16;   //3
        }
        switch (index) {
            case 0 : return;
            case 1 : minPt = occupyPt1; maxPt = occupyPt1; break;
            case 2 : minPt = occupyPt2; maxPt = occupyPt2; break;
            case 3 : minPt = Vec3(occupyPt2.x, occupyPt2.y, occupyPt2.z); maxPt = Vec3(occupyPt1.x, occupyPt1.y, occupyPt1.z); break;
            case 7 : minPt = Vec3(occupyPt1.x, occupyPt2.y, occupyPt2.z); maxPt = Vec3(occupyPt2.x, occupyPt1.y, occupyPt1.z); break;
            case 11: minPt = Vec3(occupyPt2.x, occupyPt1.y, occupyPt2.z); maxPt = Vec3(occupyPt1.x, occupyPt2.y, occupyPt1.z); break;
            case 19: minPt = Vec3(occupyPt2.x, occupyPt2.y, occupyPt1.z); maxPt = Vec3(occupyPt1.x, occupyPt1.y, occupyPt2.z); break;
            case 15: minPt = Vec3(occupyPt1.x, occupyPt1.y, occupyPt2.z); maxPt = Vec3(occupyPt2.x, occupyPt2.y, occupyPt1.z); break;
            case 23: minPt = Vec3(occupyPt1.x, occupyPt2.y, occupyPt1.z); maxPt = Vec3(occupyPt2.x, occupyPt1.y, occupyPt2.z); break;
            case 27: minPt = Vec3(occupyPt2.x, occupyPt1.y, occupyPt1.z); maxPt = Vec3(occupyPt1.x, occupyPt2.y, occupyPt2.z); break;
            case 31: minPt = Vec3(occupyPt1.x, occupyPt1.y, occupyPt1.z); maxPt = Vec3(occupyPt2.x, occupyPt2.y, occupyPt2.z); break;
        }
        occupyPt1 = maxPt; occupyPt2 = minPt;
    }   //通过两坐标获取最小和最大对角
}

class XLand {
    private:
        struct Node {
            XLand*  land;
            Node*  left;
            Node*  right;
        };

        static vector<XLand> landList;      //领地列表
        static vector<Node*> nodeVector;    //kd树节点指针
        static bool          isInitDB;      //是否成功初始化数据库 
        static Node*         rootNode;      //根节点
        static XLand*        default_land;  //空引用指针
        //构建K-D树
        static Node* build(const vector<XLand>::iterator& begin, const vector<XLand>::iterator& end, int depth);   
        static inline bool contains(Node* node, const Vec3& point, XLand*& land, int depth);         //搜索点
        //搜索范围
        static inline bool searchRange(Node* root, const Vec3& minPt, const Vec3& maxPt, XLand*& land, int depth); 
        static void clearNodeVector();                                                               //释放树内存
        XLand(long id, string name, mce::UUID owner, Vec3 pt1, Vec3 pt2, long balance);              //构建领地

    public:
        struct Mess {
            long      id;
            mce::UUID form;
            long      to;
            int       type;
            string    title;
            string    content;
            int       status;
            long long money = 0;
        };
        long      id       = 0;             //领地ID
        string    name        ;             //领地名称
        mce::UUID owner       ;             //领地主人
        Vec3      minPt       ;             //最小对角坐标
        Vec3      maxPt       ;             //最大对角坐标
        Vec3      teleport    ;             //传送到的坐标位置
        bool      pENTERLand  ;             //进入领地提示
        bool      pistonPush  ;             //活塞是否可推动
        bool      explode     ;             //是否可爆炸
        bool      liquidFlow  ;             //是否可流动
        long      balance  = 0;             //国库余额
        long      area        ;             //面积

        static unique_ptr<SQLite::Database> db;                                                       //领地数据库 SQLite
        static unique_ptr<ll::data::KeyValueDB> playerNameDb;                                         //玩家名称数据库
        static bool initDB();                                                                         //初始化数据库
        static void buildLand();                                                                      //构建领地数据
        static bool isInLand(const Vec3& point, XLand*& land);                                        //是否在领地中
        static bool hasLandIntersection(const Vec3& pt1, const Vec3& pt2, XLand*& land);              //查询与领地是否有交集
        static shared_ptr<vector<XLand>> listLand(const mce::UUID& uuid);                             //列出领地
        static string listLandStr(const Player* player);                                              //列出领地
        static shared_ptr<vector<XLand>> searchLand(const string& key);                               //搜索领地
        static bool isOwner(const long& landId,const mce::UUID& uuid);                                //是否是领地主人
        static bool isDebt(const mce::UUID& uuid);                                                    //是否有未处理的债务
        static int  removeLand(const long& landId,const mce::UUID& uuid);                             //移除领地
        //设置领地权限/信息
        static int  setLand(const long& landId,const nlohmann::json& json, const mce::UUID& uuid = 0, bool setPerm = true); 
        static void charge();                                                                         //征收保护费
        static bool formMess(const Mess& mess);                                                       //发送消息
        static bool upDateMess(const long& id, const int& status);                                    //更新信息
        static long getLandId(const string& value);                                                   //通过值获取领地ID
        static vector<long> getLand(const Player& player, bool isOwner = true);                       //获取玩家所有领地
        static vector<long> getLand(const mce::UUID& uuid, bool isOwner = true);
        static vector<Mess> getMess(const long& landId, string where = "");                           //获取玩家所有领地消息
        
        XLand(Vec3 pt1, Vec3 pt2, Vec3 teleport, mce::UUID owner, string name);                       //用户构建新领地
        XLand(const long& landId);                                                                    //数据库构建新领地
        void renew();                                                                                 //刷新领地数据
        bool isInThisLand(const Vec3& pos);                                                           //点是否在领地中
        bool isInThisLand(Player* pl);                                                                //玩家是否在领地中
        int  addLand();                                                                               //添加新领地
        void tpLand(Player& player) const;                                                            //传送到领地
        int  getDistance(const Player& player);                                                       //获取距离
        void shiftLand(const mce::UUID newOwner);                                                     //转让领地
        void reBorder(int dimId  = 0, enum ParticleCUI::ColorPalette color = ParticleCUI::ColorPalette::GREEN);
        string getLandName();                                                                         //获取领地名称
        string getOwnerName();                                                                        //获取领主名称
        nlohmann::json getJson();                                                                     //获取json格式领地数据
        
};

class LandPerm {
    private:
        
    public:
        map<string, bool*> perm;         //成员权限映射
        long id;                         //领地ID
        bool playerAttac  = false;       //发起攻击
        bool destroyBlock = false;       //破坏方块
        bool pickUpItem   = false;       //拾取掉落物
        bool placeBlock   = false;       //放置方块
        vector<string> useItems  ;       //允许交互/使用物品
        vector<string> useBlocks ;       //允许交互/使用方块
        vector<string> useEntitys;       //允许交互/使用实体

        LandPerm();
        LandPerm(const long& landId, const mce::UUID& uuid);
        void reLandPerm(const long& landId, const mce::UUID& uuid);      //刷新玩家领地权限
        nlohmann::json getJson();
        string getStr();
};

class PlayerDate {
    private:
        bool isOccupyPt2 = false;                          //是否选点Pt2
        int  occupyPtindex = 0  ;                          //正在选点

    public:
        static map<mce::UUID, PlayerDate*> playerDate;     //玩家数据
        static PlayerDate* getPlayerDate(mce::UUID uuid);  //获取玩家数据指针
        
        PlayerDate();
        bool   isOccupying  = false  ;                     //是否正在占领领地
        long   inAttackLand = 0      ;                     //正在进攻中的领地
        Vec3   occupyPt1             ;                     //占领点1
        Vec3   occupyPt2             ;                     //占领点2
        Vec3   landpos               ;                     //领地位置
        bool   isInLand     = false  ;                     //是否在领地
        long   lastLandId   = 0      ;                     //最近一次所在领地
        int    setPt(const Vec3& pos, int pt);             //设置占领点
        bool   reOccpyMode();                              //刷新占领模式
                                                           //刷新边界显示
        void   reBorder(int dimId  = 0, enum ParticleCUI::ColorPalette color = ParticleCUI::ColorPalette::GREEN);
        int64  bossId       = 0;
};
